package cn.bigcontainer.alt.meta.po;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * 对象属性，和数据库字段映射，不会存在单独的表中，作为json保存在cn.bigcontainer.alt.meta.po.MObject#mProperties中
 * @author cailei
 * @date 2019-12-04
 */

import cn.bigcontainer.alt.common.entity.BigMap;
import cn.bigcontainer.alt.common.util.WoDateKit;
import cn.bigcontainer.alt.common.util.WoKit;
import cn.bigcontainer.alt.meta.dto.MObjectDto;
import cn.bigcontainer.alt.meta.dto.MySqlColumn;
import cn.bigcontainer.alt.meta.util.MConstant;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MProperty implements Comparable<MProperty> {

	/**
	 * 类型：文本
	 */
	public final static String TYPE_VARCHAR = "VARCHAR";
	/**
	 * 类型：超大文本
	 */
	public final static String TYPE_TEXT = "TEXT";
	/**
	 * 类型：小整型
	 */
	public final static String TYPE_SMALLINT = "SMALLINT";
	/**
	 * 类型：整型
	 */
	public final static String TYPE_INTEGER = "INTEGER";
	/**
	 * 类型：数字
	 */
	public final static String TYPE_NUMERIC = "NUMERIC";
	/**
	 * 类型：日期
	 */
	public final static String TYPE_DATE = "DATE";
	/**
	 * 类型：日期时间
	 */
	public final static String TYPE_DATETIME = "DATETIME";

	/**
	 * woData中的值参数
	 */
	public final static String PARAM_VALUE = "woValue";

	/**
	 * woData中的值参数
	 */
	public final static String PARAM_ID_AUTO = "idAuto";

	public MProperty clone () {
		MProperty p = new MProperty();
		WoKit.cloneBySetter(this, p);
		return p;
	}

	private String id;

	private String name;

	/**
	 * 属性类型，例如：VARCHAR/NUMERIC
	 */
	private String type;

	/**
	 * 属性类型详情，对于VARCHAR/NUMERIC，例如：100/10,2
	 */
	private String typeDetail;

	private Integer key;

	private Integer mandatory;

	private Integer unique;

	private String max;

	private String min;

	private String defaultValue;

	private Integer index;

	private String description;

	private BigMap<String, Object> data = new BigMap<>();

	/**
	 * 内存数据，无需序列化
	 */
	@JsonIgnore
	private MObjectDto object;

	/**
	 * 文本、整型类型属性的长度
	 *
	 * @return
	 */
	@JsonIgnore
	public Integer getLength() {
		if (this.type.equals(TYPE_INTEGER)) {
			return 8;
		}
		if (this.type.equals(TYPE_SMALLINT)) {
			return 4;
		}
		if (this.type.equals(TYPE_VARCHAR)) {
			return WoKit.getInt(this.typeDetail, null);
		}
		return null;
	}

	/**
	 * 数字类型属性的位数（包含小数点位数），例如，numeric(10,2)，precision = 10
	 *
	 * @return
	 */
	@JsonIgnore
	public Integer getPrecision() {
		if (this.type.equals(TYPE_NUMERIC)) {
			String[] arr = this.typeDetail.split(",");
			return WoKit.getInt(arr[0], null);
		}
		return null;
	}

	/**
	 * 数字类型属性的小数位数，例如，numeric(10,2)，scale = 2
	 *
	 * @return
	 */
	@JsonIgnore
	public Integer getScale() {
		if (this.type.equals(TYPE_NUMERIC)) {
			String[] arr = this.typeDetail.split(",");
			return WoKit.getInt(arr[1], null);
		}
		return null;
	}

	public static String getSqlValue(String type, Object value) {
		if (value == null || (value.equals("") && (type.equals(TYPE_DATETIME) || type.equals(TYPE_NUMERIC)
				|| type.equals(TYPE_SMALLINT) || type.equals(TYPE_INTEGER)))) {
			return "null";
		}
		if (type.equals(TYPE_VARCHAR) || type.equals(TYPE_TEXT)) {
			value = value.toString().replaceAll("'", "''");
			return "'" + value + "'";
		}
		if (type.equals(TYPE_DATETIME)) {
			if (WoDateKit.isDate(value)) {
				value = value + " 00:00:01";
			}
			return "'" + value + "'";
		}
		return value.toString();
	}

	/**
	 * @param value
	 * @return
	 */
	public String getSqlValue(Object value) {
		return getSqlValue(this.getType(), value);
	}

	/**
	 * @return
	 */
	@JsonIgnore
	public String getSqlValue () {
		return getSqlValue(this.getValue());
	}

	/**
	 * @return
	 */
	@JsonIgnore
	public Object getValue() {
		return this.getData().get(PARAM_VALUE);
	}

	public void setValue (Object value) {
		data.put(PARAM_VALUE, value);
	}

	@JsonIgnore
	public String getSqlFieldClause(MObject object) {
		String metaType = this.getType();
		String dbType = null;
		String fieldsClause = this.getName() + " ";
		String M_DEFAULT = this.getDefaultValue();
		dbType = MySqlColumn.getTypeByLogicType(metaType);
		// column
		if (metaType.equals(TYPE_VARCHAR) || metaType.equals(TYPE_NUMERIC)) {
			fieldsClause += dbType + "(" + this.getTypeDetail() + ")";
		} else {
			fieldsClause += dbType;
		}
		// null
		int M_MANDATORY = this.getMandatory();
		if (!MObjectDto.isLogicDelete(object) && M_MANDATORY == 1) {
			fieldsClause += " NOT NULL ";
		}
		// default
		if (!WoKit.isEmpty(M_DEFAULT) && !MConstant.DEFAULT_CURRENT_TIME.equals(M_DEFAULT)) {
			fieldsClause += " DEFAULT ";
			if (metaType.equals(TYPE_VARCHAR)
					|| (metaType.equals(TYPE_DATETIME) && !M_DEFAULT.startsWith(MConstant.DEFAULT_CREATE_TIME_SQL))) {
				fieldsClause += "'" + M_DEFAULT + "'";
			} else if (metaType.equals(TYPE_INTEGER)) {
				fieldsClause += WoKit.getDouble(M_DEFAULT.toString()).intValue();
			} else {
				fieldsClause += M_DEFAULT;
			}
		}
		// 自增长
		if (isIdAuto() && metaType.equals(TYPE_INTEGER)) {
			fieldsClause += " AUTO_INCREMENT ";
		}
		if (!WoKit.isEmpty(this.description)) {
			fieldsClause += " COMMENT '" + description + "'";
		}
		return fieldsClause;
	}

	@JsonIgnore
	public String getDropSql(MObject object) {
		return String.format("alter table %s drop column %s", object.getId(), this.getName());
	}
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getTypeDetail() {
		return typeDetail;
	}

	public void setTypeDetail(String typeDetail) {
		this.typeDetail = typeDetail;
	}

	public Integer getKey() {
		return key;
	}

	public void setKey(Integer key) {
		this.key = key;
	}

	public Integer getMandatory() {
		return mandatory;
	}

	public void setMandatory(Integer mandatory) {
		this.mandatory = mandatory;
	}

	public Integer getUnique() {
		return unique;
	}

	public void setUnique(Integer unique) {
		this.unique = unique;
	}

	public String getMax() {
		return max;
	}

	public void setMax(String max) {
		this.max = max;
	}

	public String getMin() {
		return min;
	}

	public void setMin(String min) {
		this.min = min;
	}

	public String getDefaultValue() {
		return defaultValue;
	}

	public void setDefaultValue(String defaultValue) {
		this.defaultValue = defaultValue;
	}

	public Integer getIndex() {
		return index;
	}

	public void setIndex(Integer index) {
		this.index = index;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public BigMap<String, Object> getData() {
		return data;
	}

	public void setData(BigMap<String, Object> data) {
		this.data = data;
	}

	public MObjectDto getObject() {
		return object;
	}

	public void setObject(MObjectDto object) {
		this.object = object;
	}

	@JsonIgnore
	public Boolean getMetaShow () {
		return data.getBoolean(MObjectDto.PARAM_META_SHOW, false);
	}

	public void setMetaShow (Boolean metaShow) {
		data.put(MObjectDto.PARAM_META_SHOW, metaShow);
	}

	@Override
	public int compareTo(MProperty o) {
		return this.getIndex() - o.getIndex();
	}

	@JsonIgnore
	public String getNameCamelCase () {
		return WoKit.getCamelCase(this.name, false);
	}

	@JsonIgnore
	public String getJavaType () {
		String javaType = "String";
		switch (type) {
			case TYPE_DATE:
			case TYPE_DATETIME:
				javaType = "java.util.Date";
				break;
			case TYPE_SMALLINT:
			case TYPE_INTEGER:
				javaType = "Integer";
				break;
			case TYPE_NUMERIC:
				javaType = "Double";
				break;
		}
		return javaType;
	}

	/**
	 * id是否由数据库自动生成
	 * @return
	 */
	@JsonIgnore
	public Boolean isIdAuto () {
		return data.getBoolean(PARAM_ID_AUTO, false);
	}
}
